package gomysql

import (
	"fmt"
	"go-micro-framework/go_service/core/gomodel"
	"go-micro-framework/go_service/core/gomysql/internal"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/schema"
	"gorm.io/gorm/utils"
	"log"
	"reflect"
)

var db *gorm.DB

type DBId interface {
	GetId() int64
}

func GetDB() *gorm.DB {
	//if config.MysqlDSN == "*" {
	//	println("gorm not init! because MysqlUri is * or gorm is ''")
	//	return
	//}
	if db != nil {
		return db
	}
	db, err := gorm.Open(mysql.Open(MysqlDSN), &gorm.Config{})
	//db, err := gorm.Open(mysql.New(mysql.Config{
	//	DSN:                       config.Instance.DB.DSN, // DSN data source name
	//	DefaultStringSize:         256,                    // string 类型字段的默认长度
	//	DisableDatetimePrecision:  true,                   // 禁用 datetime 精度，MySQL 5.6 之前的数据库不支持
	//	DontSupportRenameIndex:    true,                   // 重命名索引时采用删除并新建的方式，MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
	//	DontSupportRenameColumn:   true,                   // 用 `change` 重命名列，MySQL 8 之前的数据库和 MariaDB 不支持重命名列
	//	SkipInitializeWithVersion: false,                  // 根据当前 MySQL 版本自动配置
	//}), &config.Instance.DB.Config)
	if err != nil {
		log.Println(err)
	}
	log.Println(db, err)
	// 初始化gplus
	//var u User
	//db.AutoMigrate(u)
	return db
}

// objType 实现了 CustomInterface 接口 返回true,
// objType 没有实现 CustomInterface 接口 返回 false
func ObjectImpl(entity any) bool {
	objType := reflect.TypeOf(entity)
	intType := reflect.TypeOf((*DBId)(nil)).Elem()
	var ok = objType.Implements(intType)
	fmt.Println(ok)
	return ok
}

/** GetId 函数通用实现,获取对象的id值 通过对象获取接口类的GetId()的值 **/
func GetId(entity DBId) int64 {
	return entity.GetId()
}
func getPkColumnName[T any]() string {
	var entity T
	entityType := reflect.TypeOf(entity)
	numField := entityType.NumField()
	var columnName string
	for i := 0; i < numField; i++ {
		field := entityType.Field(i)
		tagSetting := schema.ParseTagSetting(field.Tag.Get("gorm"), ";")
		isPrimaryKey := utils.CheckTruth(tagSetting["PRIMARYKEY"], tagSetting["PRIMARY_KEY"])
		if isPrimaryKey {
			name, ok := tagSetting["COLUMN"]
			if !ok {
				namingStrategy := schema.NamingStrategy{}
				name = namingStrategy.ColumnName("", field.Name)
			}
			columnName = name
			break
		}
	}
	if columnName == "" {
		return internal.DefaultPrimaryName
	}
	return columnName
}

/** 通过指针获取泛型类的GetId()的值 **/
func GetId2[T any](entity *T) int64 {
	objType := reflect.TypeOf(entity)
	intType := reflect.TypeOf((*DBId)(nil)).Elem()
	var ok = objType.Implements(intType)
	//var ok = ObjectImpl(entity)
	if !ok {
		return 0
	}
	object := reflect.ValueOf(entity)
	result := object.MethodByName("GetId").Call(nil)
	if result == nil {
		return 0
	}
	iValue := result[0].Interface()
	return iValue.(int64)
}
func getBatchSize(batchSize ...int) int {
	if batchSize == nil || batchSize[0] == 0 || len(batchSize) != 1 || batchSize[0] > MYSQL_BATCH_SIZE {
		return MYSQL_BATCH_SIZE
	}
	return batchSize[0]
}

/*
*保存一条记录的方法
//var user *UserId = &UserId{Name: "Jinzhu", Age: 18, Birthday: time.Now()}
*/
func Save[T any](entity *T) (int64, *gorm.DB) {
	result := GetDB().Create(entity) // 通过数据的指针来创建
	if result.Error != nil {
		return 0, result
	}
	var id = GetId2(entity)
	return id, result
}

/*
*
  - 批量保存方法,并返回列表的主键的方法
    EG: users := []User{
    User{Name: "Jinzhu", Age: 18, Birthday: time.Now()},
    User{Name: "Jackson", Age: 19, Birthday: time.Now()},
    }
*/

func SaveBatchId[T any](entityList []*T, batchSize ...int) ([]int64, *gorm.DB) {
	var size = getBatchSize(batchSize...)
	result := GetDB().CreateInBatches(entityList, size) // 通过数据的指针来创建
	if result.Error != nil {
		return nil, result
	}
	idList := make([]int64, len(entityList))
	for i := 0; i < len(entityList); i++ {
		idList[i] = GetId2(entityList[i])
	}
	return idList, result
}

/*
*
  - 批量保存方法,只返回成功或失败的方法
    EG: users := []User{
    User{Name: "Jinzhu", Age: 18, Birthday: time.Now()},
    User{Name: "Jackson", Age: 19, Birthday: time.Now()},
    }
*/
func SaveBatch(entityList any, batchSize ...int) (bool, *gorm.DB) {
	//user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}
	var size = getBatchSize(batchSize...)
	result := GetDB().CreateInBatches(entityList, size) // 通过数据的指针来创建
	if result.Error != nil {
		return false, result
	}
	return true, result
}

/*
*保存一条记录的方法,因为没有不会触发 AfterCreate、BeforeCreate 等 hooks（钩子）函数。
同时，GORM 也不会自动保存关联表的信息，例如外键关联等。此外，GORM 也不会回填主键值。
//&User{} ,map[string]interface{}{"Name": "jinzhu_Map", "Age": 28,}
*/
func SaveModel(entity any, entityKeyValue map[string]any) (bool, *gorm.DB) {
	result := GetDB().Model(&entity).Create(entityKeyValue) // 通过数据的指针来创建
	if result.Error != nil {
		return false, result
	}
	result.Scan(&entity)
	return true, result
}

/*
*
  - 批量保存方法,并返回列表的主键的方法
    // batch insert from `[]map[string]interface{}{}`
    db.Model(&User{}).Create([]map[string]interface{}{
    {"Name": "jinzhu_1", "Age": 18},
    {"Name": "jinzhu_2", "Age": 20},
    })

因为没有不会触发 AfterCreate、BeforeCreate 等 hooks（钩子）函数。
同时，GORM 也不会自动保存关联表的信息，例如外键关联等。此外，GORM 也不会回填主键值。
*/
func SaveModelBatch(entity any, entityKeyValueList map[string]any) (bool, *gorm.DB) {
	result := GetDB().Model(&entity).Create(entityKeyValueList) // 通过数据的指针来创建
	if result.Error != nil {
		return false, result
	}
	return true, result
}

/*** ------------------------删除----------------------------------------- **/

// DeleteById 根据 ID 删除记录
/**
db.Delete(&User{}, 10)
// DELETE FROM users WHERE id = 10;
*/
func DeleteById[T any](id int64) (bool, *gorm.DB) {
	var dbId T
	result := GetDB().Delete(&dbId, id)
	if result.Error == nil {
		return true, result
	}
	return false, result
}

// DeleteById 根据 ID 删除记录
/**
// Email 的 ID 是 `10`
db.Delete(&email)
// DELETE from emails where id = 10;
*/
func DeleteByDBId(entity DBId) (bool, *gorm.DB) {
	var id = GetId(entity)
	result := GetDB().Delete(&entity, id)
	if result.Error == nil {
		return true, result
	}
	return false, result
}

// DeleteByIds 根据 ID 批量删除记录
// DELETE FROM users WHERE id IN (1,2,3);
func DeleteByIds[T any](ids ...int64) (bool, *gorm.DB) {
	if len(ids) <= 1 {
		return DeleteById[T](ids[0])
	}
	var entity T
	result := GetDB().Delete(&entity, ids)
	if result.Error == nil {
		return true, result
	}
	return false, result
}

// DeleteByIds 根据 ID 批量删除记录
// DELETE FROM users WHERE id IN (1,2,3);
func DeleteByArrayId[T any](ids []int64) (bool, *gorm.DB) {
	if len(ids) == 1 {
		return DeleteById[T](ids[0])
	}
	var entities []T
	result := GetDB().Delete(&entities, ids)
	if result.Error == nil {
		return true, result
	}
	return false, result
}

// DeleteByQuery 根据 查询条件 批量删除记录
// DELETE FROM users WHERE id IN (1,2,3);
func DeleteByQuery[T any](q *QueryWrapper[T]) (bool, *gorm.DB) {
	var entity T
	result := SelectQueryWrapper(q).Delete(&entity)
	if result.Error == nil {
		return true, result
	}
	return false, result
}

/*
*保存一条记录的方法
* 如果user表id为0或不存在时,执行插入语句,
* db.Save(&User{Name: "jinzhu", Age: 100})
* INSERT INTO `users` (`name`,`age`,`birthday`,`update_at`) VALUES ("jinzhu",100,"0000-00-00 00:00:00","0000-00-00 00:00:00")
* 如果user表id>0时,执行更新语句,
* db.Update(&User{ID: 1, Name: "jinzhu", Age: 100})
* UPDATE `users` SET `name`="jinzhu",`age`=100,`birthday`="0000-00-00 00:00:00",`update_at`="0000-00-00 00:00:00" WHERE `id` = 1
***
** 对象的字段为空时,不执行变更
 */
func SaveOrUpdate[T any](entity *T) (int64, *gorm.DB) {
	//user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}
	result := GetDB().Save(entity) // 通过数据的指针来创建
	if result.Error != nil {
		return 0, result
	}
	var id = GetId2(&entity)
	return id, result
}

/*
*保存一条记录的方法
* 如果user表id为0或不存在时,执行插入语句,
* db.Save(&User{Name: "jinzhu", Age: 100})
* INSERT INTO `users` (`name`,`age`,`birthday`,`update_at`) VALUES ("jinzhu",100,"0000-00-00 00:00:00","0000-00-00 00:00:00")
* 如果user表id>0时,执行更新语句,
* db.Update(&User{ID: 1, Name: "jinzhu", Age: 100})
* UPDATE `users` SET `name`="jinzhu",`age`=100,`birthday`="0000-00-00 00:00:00",`update_at`="0000-00-00 00:00:00" WHERE `id` = 1
***
** 对象的字段为空时,不执行变更
 */
func Update[T any](entity *T) (bool, *gorm.DB) {
	//user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}
	result := GetDB().Updates(entity) // 通过数据的指针来创建
	if result.Error != nil {
		return false, result
	}
	return true, result
}

// Update with conditions
// Update attributes with `map`
// db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
// UPDATE users SET name='hello', age=18, active=false, updated_at='2013-11-17 21:34:10' WHERE id=111;
func UpdateModel[T any](q *QueryWrapper[T], updateDate map[string]any) *gorm.DB {
	return SelectQueryWrapper(q).Updates(updateDate)
}

// SelectById 根据 ID 查询单条记录
// SELECT * FROM users WHERE id = 10;
func SelectById[T any](id int64) (*T, *gorm.DB) {
	var entity T
	result := GetDB().First(&entity, id)
	return &entity, result
}

// SelectByIds 根据 ID 查询多条记录
// SELECT * FROM `entity_company` WHERE `entity_company`.`id` IN (2,3,4)
func SelectByIds[T any](ids []int64) ([]*T, *gorm.DB) {
	var entities []*T
	result := GetDB().Find(&entities, ids)
	return entities, result
}

// SelectByIds 根据 ID 查询多条记录
// SELECT * FROM `entity_company` WHERE `entity_company`.`id` IN (2,3,4)
func SelectByIdsToMap[T any](ids []int64) (map[int64]*T, *gorm.DB) {
	var entities []*T
	result := GetDB().Find(&entities, ids)
	if result.Error != nil {
		return nil, result
	}
	var entityMap = make(map[int64]*T, len(entities))
	for _, key := range entities {
		var id = GetId2(key)
		entityMap[id] = key
	}
	return entityMap, result
}

// SelectOne 根据条件查询单条记录
// SELECT count(*) FROM `entity_company` WHERE company_id = 1 AND store_code = 'Jinzhu33'
func SelectCount[T any](q *QueryWrapper[T]) (int64, *gorm.DB) {
	var count int64
	result := SelectQueryWrapper(q).Count(&count)
	return count, result
}

// SelectOne 根据条件查询单条记录,默认为升序
// SELECT * FROM `entity_company` WHERE company_id = 21 AND store_code = 'Jinzhu33'  LIMIT 1
func SelectOne[T any](q *QueryWrapper[T]) (*T, *gorm.DB) {
	var entity T
	result := SelectQueryWrapper(q).Take(&entity)
	return &entity, result
}

// SelectOne 根据条件查询单条记录
func SelectFirst[T any](q *QueryWrapper[T]) (*T, *gorm.DB) {
	var entity *T
	result := SelectQueryWrapper(q).First(&entity)
	return entity, result
}

// SelectOne 根据条件查询单条记录
func SelectLast[T any](q *QueryWrapper[T]) (*T, *gorm.DB) {
	var entity *T
	result := SelectQueryWrapper(q).Last(&entity)
	return entity, result
}

// Selectpage 根据条件查询单条记录
func GetQueryPage[T any](page *QueryPage[T]) *QueryPage[T] {
	if page == nil {
		page = NewQueryPage[T]()
	}
	return page
}

// SelectList 根据条件查询多条记录,无分页
// SELECT * FROM `entity_company` WHERE company_id = 21 AND store_code = 'Jinzhu33'
func SelectList[T any](q *QueryWrapper[T]) ([]*T, *gorm.DB) {
	var entities []*T
	result := SelectQueryWrapper(q).Find(&entities)
	return entities, result
}

// Selectpage 根据条件查询单条记录
// SELECT * FROM `entity_company` WHERE company_id = 21 AND store_code = 'Jinzhu33'  LIMIT 3 OFFSET 3
func SelectListByPage[T any](q *QueryWrapper[T], page *QueryPage[T]) ([]*T, *gorm.DB) {
	var entities []*T
	page = GetQueryPage(page)
	result := SelectQueryWrapper(q).
		Offset(page.GetOffset()).
		Limit(page.GetLimit()).
		Find(&entities)
	return entities, result
}

// Selectpage 根据条件查询单条记录
func SelectListByPageIsNext[T any](q *QueryWrapper[T], page *QueryPage[T]) (*QueryPage[T], *gorm.DB) {
	var entities []*T
	page = GetQueryPage(page)
	result := SelectQueryWrapper(q).
		Offset(page.GetOffset()).
		Limit(page.GetLimit()).
		Find(&entities)
	page.ProcessRecordsNextPage(entities)
	if page.IsSearchCount {
		total, countDb := SelectCount[T](q)
		if countDb.Error != nil {
			return page, countDb
		}
		page.Total = total
	}
	return page, result
}

// Selectpage 根据条件查询单条记录,统一分页列表结果规范的对象
func SelectResultListByPage[T any](q *QueryWrapper[T], page *QueryPage[T]) *gomodel.ResponseResultList {
	var entities []*T
	q.ExplainQueryWrapper()
	//var whereValue = q.GetWhereValue()[:]
	page = GetQueryPage(page)
	result := SelectQueryWrapper(q).
		Offset(page.GetOffset()).
		Limit(page.GetLimit()).
		Find(&entities)
	if result.Error != nil {
		return nil
	}
	var resultList = page.ProcessResponseResultList(entities)
	if page.IsSearchCount {
		total, countDb := SelectCount[T](q)
		if countDb.Error != nil {
			return &resultList
		}
		resultList.SetTotal(total)
		page.Total = total
	}
	return &resultList
}

// result := GetDB().Where(q.GetWhere(), whereValue...).
// Limit(page.GetLimit()).Offset(page.GetOffset()).Find(&entities)
func SelectQueryWrapper[T any](q *QueryWrapper[T]) *gorm.DB {

	sql := GetDB().Model(new(T))
	if q != nil {
		// 这里清空参数，避免用户重复使用一个query条件
		q.whereArgs = make([]any, 0)

		if len(q.selects.distinctColumns) > 0 {
			sql.Distinct(q.selects.distinctColumns)
		}

		if len(q.selects.selectColumns) > 0 {
			sql.Select(q.selects.selectColumns)
		}

		if len(q.selects.omitColumns) > 0 {
			sql.Omit(q.selects.omitColumns...)
		}

		whereSqlQuery := q.whereSqlQuery
		if len(whereSqlQuery) > 0 {
			q.ExplainQueryWrapper()
			sql.Where(q.whereFormat, q.whereArgs...)

		}

		if q.orderBuilder.Len() > 0 {
			sql.Order(q.orderBuilder.String())
		}

		if q.groupBuilder.Len() > 0 {
			sql.Group(q.groupBuilder.String())
		}

		if q.havingBuilder.Len() > 0 {
			sql.Having(q.havingBuilder.String(), q.havingArgs...)
		}
	}
	return sql
}
